package 多线程;

import java.util.Collection;
import java.util.List;
/*
ExecutorService的继承关系
public interface ExecutorService extends Executor, AutoCloseable {
	void shutdown();
	List<Runnable> shutdownNow();
	boolean isShutdown();
	<T> Future<T> submit(Callable<T> task);
	Future<?> submit(Runnable task);
	default void close() {
	...
}
public interface Executor {
    void execute(Runnable command);
}
public interface AutoCloseable {
    void close() throws Exception;
}

2、ExecutorService的创建及使用
Java给我们提供了一个Executors工厂类，它可以帮助我们很方便的创建各种类型ExecutorService线程池，Executors一共可以创建下面这四类线程池：
1. newCachedThreadPool 创建一个可缓存线程池，如果线程池长度超过处理需要，可灵活回收空闲线程，若无可回收，则新建线程。
2. newFixedThreadPool 创建一个定长线程池，可控制线程最大并发数，超出的线程会在队列中等待。
3. newScheduledThreadPool 创建一个定长线程池，支持定时及周期性任务执行。
4. newSingleThreadExecutor 创建一个单线程化的线程池，它只会用唯一的工作线程来执行任务，保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。
2.1 newCachedThreadPool
该方法返回一个可根据实际情况调整线程数量的线程池。
线程池的线程数量不确定，但若有空闲线程可以复用，则会优先使用可复用的线程。
若所有线程均在工作，又有新任务的提交，则会创建新的线程处理任务。
所有线程在当前任务执行完毕后，将返回线程池进行复用
创建一个可缓存线程池，如果线程池长度超过处理需要，可灵活回收空闲线程，若无可回收，则新建线程。示例代码如下

ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
for (int i = 0; i < 10; i++) {
    final int index = i;
    try {
        Thread.sleep(index * 1000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    cachedThreadPool.execute(new Runnable() {
        @Override
        public void run() {
            System.out.println(index);
        }
    });
}
cachedThreadPool.shutdown();

2.2 newFixedThreadPool
创建一个定长线程池，可控制线程最大并发数，超出的线程会在队列中等待。示例代码如下：
该方法返回一个固定线程数量的线程池，该线程池池中的线程数量始终不变。
当有一个新的任务提交时，线程池中若有空闲线程，则立即执行。
若没有，则新的任务会被暂存在一个任务队列中，待有线程空闲时，便处理在任务队列中的任务 
默认等待队列长度为Integer.MAX_VALUE

ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
for (int i = 0; i < 10; i++) {
    final int index = i;
    fixedThreadPool.execute(new Runnable() {
 
        @Override
        public void run() {
            try {
                System.out.println(index);
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    });
}
fixedThreadPool.shutdown();

因为线程池大小为3，每个任务输出index后sleep 2秒，所以每两秒打印3个数字。
定长线程池的大小最好根据系统资源进行设置。如Runtime.getRuntime().availableProcessors()。可参考PreloadDataCache。

2.3 newScheduledThreadPool
创建一个定长线程池，支持定时及周期性任务执行。

延迟执行示例代码如下：

ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
scheduledThreadPool.schedule(new Runnable() {
    @Override
    public void run() {
        System.out.println("delay 3 seconds");
    }
}, 3, TimeUnit.SECONDS); //表示延迟3秒执行
scheduledThreadPool.shutdown();
定期执行示例代码如下：

scheduledThreadPool.scheduleAtFixedRate(new Runnable() {
    @Override
    public void run() {
        System.out.println("delay 1 seconds, and excute every 3 seconds");
    }
}, 1, 3, TimeUnit.SECONDS);
表示延迟1秒后每3秒执行一次。ScheduledExecutorService比Timer更安全，功能更强大。

2.4 newSingleThreadExecutor
该方法返回一个只有一个线程的线程池。
若多余一个任务被提交到线程池，任务会被保存在一个任务队列中，等待线程空闲，按先入先出顺序执行队列中的任务
默认等待队列长度为Integer.MAX_VALUE
创建一个单线程化的线程池，它只会用唯一的工作线程来执行任务，保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。示例代码如下：

ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
for (int i = 0; i < 10; i++) {
    final int index = i;
    singleThreadExecutor.execute(new Runnable() {
        @Override
        public void run() {
            try {
                System.out.println(index);
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    });
}
singleThreadExecutor.shutdown();

2.5 newSingleThreadScheduledExecutor()
该方法返回一个ScheduledExecutorService对象，线程池大小为1。
ScheduledExecutorService接口在ExecutorService接口之上扩展了在给定时间内执行某任务的功能，
如在某个固定的延时之后执行，或者周期性执行某个任务

ExecutorService newSingleThreadScheduledExecutor = Executors.newSingleThreadScheduledExecutor();

该方法也返回一个ScheduledExecutorService对象，但该线程池可以指定线程数量
ExecutorService newScheduledThreadPool = Executors.newScheduledThreadPool(1);

结果依次输出，相当于顺序执行各个任务。现行大多数GUI程序都是单线程的。Android中单线程可用于数据库操作，文件操作，应用批量安装，应用批量删除等不适合并发但可能IO阻塞性及影响UI线程响应的操作。

备注：Executors只是一个工厂类，它所有的方法返回的都是ThreadPoolExecutor、ScheduledThreadPoolExecutor这两个类的实例。

//Executers类的静态方法返回ExecutorService实例：
public class Executors {
    public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>());
    }
    public static ExecutorService newWorkStealingPool(int parallelism) {
        return new ForkJoinPool(parallelism,ForkJoinPool.defaultForkJoinWorkerThreadFactory,null, true);
    }
    public static ExecutorService newWorkStealingPool() {
        return new ForkJoinPool(Runtime.getRuntime().availableProcessors(),ForkJoinPool.defaultForkJoinWorkerThreadFactory,null, true);
    }
    public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {
        return new ThreadPoolExecutor(nThreads, nThreads,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>(),threadFactory);
    }
...
}
3、ExecutorService的执行
ExecutorService有如下几个执行方法：

- execute(Runnable)
- submit(Runnable)
- submit(Callable)
- invokeAny(...)
- invokeAll(...)
3.1 execute(Runnable)
这个方法接收一个Runnable实例，并且异步的执行，请看下面的实例：

ExecutorService executorService = Executors.newSingleThreadExecutor();
executorService.execute(new Runnable() {
public void run() {
    System.out.println("Asynchronous task");
}
});
executorService.shutdown();
这个方法存在一个问题，就是没有办法获知task的执行结果。如果我们想获得task的执行结果，我们可以传入一个Callable的实例（下面会介绍）。

3.2 submit(Runnable)
submit(Runnable)和execute(Runnable)区别是前者可以返回一个Future对象，通过返回的Future对象，我们可以检查提交的任务是否执行完毕，请看下面执行的例子：

Future future = executorService.submit(new Runnable() {
public void run() {
    System.out.println("Asynchronous task");
}
});
 
future.get();  //returns null if the task has finished correctly.
如果任务执行完成，future.get()方法会返回一个null。注意，future.get()方法会产生阻塞。

3.3 submit(Callable)
submit(Callable) 和 submit(Runnable) 类似，也会返回一个Future对象，但是除此之外，submit(Callable)接收的是一个Callable的实现，Callable接口中的call()方法有一个返回值，可以返回任务的执行结果，而Runnable接口中的run()方法是void的，没有返回值。请看下面实例：

Future future = executorService.submit(new Callable(){
public Object call() throws Exception {
    System.out.println("Asynchronous Callable");
    return "Callable Result";
}
});
 
System.out.println("future.get() = " + future.get());
如果任务执行完成，future.get()方法会返回Callable任务的执行结果。注意，future.get()方法会产生阻塞。

3.4 invokeAny(…)
invokeAny(...)方法接收的是一个Callable的集合，执行这个方法不会返回Future，但是会返回所有Callable任务中其中一个任务的执行结果。这个方法也无法保证返回的是哪个任务的执行结果，反正是其中的某一个。请看下面实例：

ExecutorService executorService = Executors.newSingleThreadExecutor();
 
Set<Callable<String>> callables = new HashSet<Callable<String>>();
 
callables.add(new Callable<String>() {
public String call() throws Exception {
    return "Task 1";
}
});
callables.add(new Callable<String>() {
public String call() throws Exception {
    return "Task 2";
}
});
callables.add(new Callable<String>() {
    public String call() throws Exception {
    return "Task 3";
}
});
 
String result = executorService.invokeAny(callables);
System.out.println("result = " + result);
executorService.shutdown();

大家可以尝试执行上面代码，每次执行都会返回一个结果，并且返回的结果是变化的，可能会返回“Task2”也可是“Task1”或者其它。

3.5 invokeAll(…)
invokeAll(...)与 invokeAny(...)类似也是接收一个Callable集合，但是前者执行之后会返回一个Future的List，其中对应着每个Callable任务执行后的Future对象。情况下面这个实例：

ExecutorService executorService = Executors.newSingleThreadExecutor();
 
Set<Callable<String>> callables = new HashSet<Callable<String>>();
 
callables.add(new Callable<String>() {
public String call() throws Exception {
    return "Task 1";
}
});
callables.add(new Callable<String>() {
    public String call() throws Exception {
    return "Task 2";
}
});
callables.add(new Callable<String>() {
public String call() throws Exception {
    return "Task 3";
}
});
 
List<Future<String>> futures = executorService.invokeAll(callables);
 
for(Future<String> future : futures){
System.out.println("future.get = " + future.get());
}
 
executorService.shutdown();

4、ExecutorService的关闭
当我们使用完成ExecutorService之后应该关闭它，否则它里面的线程会一直处于运行状态。

举个例子，如果的应用程序是通过main()方法启动的，在这个main()退出之后，如果应用程序中的ExecutorService没有关闭，这个应用将一直运行。之所以会出现这种情况，是因为ExecutorService中运行的线程会阻止JVM关闭。

如果要关闭ExecutorService中执行的线程，我们可以调用ExecutorService.shutdown()方法。在调用shutdown()方法之后，ExecutorService不会立即关闭，但是它不再接收新的任务，直到当前所有线程执行完成才会关闭，所有在shutdown()执行之前提交的任务都会被执行。

如果我们想立即关闭ExecutorService，我们可以调用ExecutorService.shutdownNow()方法。这个动作将跳过所有正在执行的任务和被提交还没有执行的任务。但是它并不对正在执行的任务做任何保证，有可能它们都会停止，也有可能执行完成。

5、ThreadPoolExecutor
ThreadPoolExecutor是ExecutorService的一个实现类，也是java中最常用的线程池类。ThreadPoolExecutor内部维持了一个线程池，可以执行给定的任务，下面是关于它的具体使用方法。

Java 线程池工作过程
线程池刚创建时，里面没有一个线程。任务队列是作为参数传进来的。不过，就算队列里面有任务，线程池也不会马上执行它们。
当调用 execute() 方法添加一个任务时，线程池会做如下判断（见下方5.2中数量控制）
当一个线程完成任务时，它会从队列中取下一个任务来执行。
当一个线程无事可做，超过一定的时间（keepAliveTime）时，线程池会判断，如果当前运
行的线程数大于 corePoolSize，那么这个线程就被停掉。所以线程池的所有任务完成后，它
最终会收缩到 corePoolSize 的大小。
5.1 ThreadPoolExecutor构造方法及其作用
ThreadPoolExecutor源码中的构造方法：
public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,threadFactory, defaultHandler);
    }

- corePoolSize：线程池维护线程的最少数量
- maximumPoolSize：线程池维护线程的最大数量
- keepAliveTime： 线程池维护线程所允许的空闲时间
- unit： 线程池维护线程所允许的空闲时间的单位
- workQueue： 线程池所使用的缓冲队列
- handler： 线程池对拒绝任务的处理策略
·corePoolSize：当提交一个任务到线程池时，线程池会创建一个线程来执行任务，即使其他空闲的基本线程能够执行新任务也会创建线程，等到需要执行的任务数大
               于线程池基本大小时就不再创建。如果调用了线程池的prestartAllCoreThreads方法，线程池会提前创建并启动所有基本线程。
·maximumPoolSize：线程池允许创建的最大线程数。如果队列满了，并且已创建的线程数小于最大线程数，则线程池会再创建新的线程执行任务。值得注意的是如果
               使用了无界的任务队列这个参数就没什么效果。
·keepAliveTime：当线程池线程数量超过corePoolSize时，多余的空余线程存活时间，即超过corePoolSize的空闲线程，在多长时间内被销毁。如果任务
               很多，并且每个任务执行的时间比较短，可以调大这个时间，提高线程的利用率。
·unit：keepAliveTime的单位。
·workQueue：任务队列，被提交但尚未被执行任务的任务。有以下几种队列模式：

1.ArrayBlockingQueue：是一个基于数组结构的有界阻塞队列，此队列按 FIFO（先进先出）原则对元素进行排序。
2.LinkedBlockingQueue：一个基于链表结构的阻塞队列，此队列按FIFO （先进先出） 排序元素，吞吐量通常要高于ArrayBlockingQueue。静态工厂方法Executors.newFixedThreadPool()使用了这个队列。
3.SynchronousQueue：一个不存储元素的阻塞队列。每个插入操作必须等到另一个线程调用移除操作，否则插入操作一直处于阻塞状态，吞吐量通常要高于LinkedBlockingQueue，静态工厂方法Executors.newCachedThreadPool使用了这个队列。
4.PriorityBlockingQueue：一个具有优先级得无限阻塞队列。

·threadFactory：线程工厂，用于创建线程，一般用默认的即可。也可以通过线程工厂给每个创建出来的线程设置更有意义的名字，Debug和定位问题时非常有帮助。
·handler：拒绝策略，当队列和线程池都满了，说明线程池处于饱和状态，那么必须采取一种策略处理提交的新任务。这个策略默认情况下是AbortPolicy，表
          示无法处理新任务时抛出异常。系统内置的策略模式如下：

1.AbortPolicy：直接抛出异常，阻止系统正常工作。
2.CallerRunsPolicy：只要线程未关闭，该策略直接在调用者线程中，运行当前被丢弃的任务。
3.DiscardOldestPolicy：该策略将丢弃最老的一个请求，也就是即将被执行的一个人任务，并尝试再次提交当前任务。
4.DiscardPolicy：该策略默默的丢弃无法处理对
5.当然也可以根据应用场景需要来实现RejectedExecutionHandler接口自定义策略。

ThreadPoolExecutor 例子：
ThreadPoolExecutor threadPool = new ThreadPoolExecutor(10, 20, 1,TimeUnit.SECONDS, 
                                              new ArrayBlockingQueue<Runnable>(15),
                                              new ThreadPoolExecutor.DiscardOldestPolicy());
上面的语句：

10是表示允许10个线程，20是最多可以有20个线程在进行或等待，1 线程池维护线程所允许的空闲时间为1秒，TimeUnt.SECONDS 线程池维护线程所允许的空闲时间
的单位以秒为单位，下一个参数是指线程池所使用的缓冲队列为有界队列，最后一次参数是线程池对拒绝任务的处理策略抛弃旧的任务.


5.2 线程数量控制
ThreadPoolExecutor线程池中的线程数量是可变的，其变化范围取决于下面两个变量：

1. corePoolSize：线程池维护线程的最少数量
2. maximumPoolSize：线程池维护线程的最大数量
具体线程的分配方式是，当一个任务被添加到线程池：

·如果此时线程池中的数量小于corePoolSize，即使线程池中的线程都处于空闲状态，也要创建新的线程来处理被添加的任务。
·如果此时线程池中的数量等于 corePoolSize，但是缓冲队列 workQueue未满，那么任务被放入缓冲队列。
·如果此时线程池中的数量大于corePoolSize，缓冲队列workQueue满，并且线程池中的数量小于maximumPoolSize，建新的线程来处理被添加的任务。
·如果此时线程池中的数量大于corePoolSize，缓冲队列workQueue满，并且线程池中的数量等于maximumPoolSize，那么通过 handler所指定的策略来处理此任务。也就是：处理任务的优先级为：核心线程corePoolSize、任务队列workQueue、最大线程maximumPoolSize，如果三者都满了，使用handler处理被拒绝的任务。
·当线程池中的线程数量大于 corePoolSize时，如果某线程空闲时间超过keepAliveTime，线程将被终止。
这样，线程池可以动态的调整池中的线程数。除了corePoolSize、maximumPoolSize两个变量外，ThreadPoolExecutor构造方法还有几个参数：

·keepAliveTime： 线程池维护线程所允许的空闲时间
·unit： 线程池维护线程所允许的空闲时间的单位
·workQueue： 线程池所使用的缓冲队列
·handler： 线程池对拒绝任务的处理策略
5.2.1 unit

unit 可选的参数为java.util.concurrent.TimeUnit中的几个静态属性：

- NANOSECONDS
- MICROSECONDS
- MILLISECONDS
- SECONDS
5.2.2 workQueue

workQueue是一个BlockingQueue，默认是LinkedBlockingQueue<Runnable>

5.2.3 handler

handler 是线程池拒绝处理任务的方式，主要有四种类型：

ThreadPoolExecutor.AbortPolicy()（系统默认）：抛出java.util.concurrent.RejectedExecutionException异常
ThreadPoolExecutor.CallerRunsPolicy()：当抛出RejectedExecutionException异常时，会调用rejectedExecution方法，只要线程池未关闭，该策略直接在调用者线程中，运行当前被丢弃的任务。显然这样做不会真的丢弃任务，但是，任务提交线程的性能极有可能会急剧下降。
ThreadPoolExecutor.DiscardOldestPolicy()：丢弃最老的一个请求，也就是即将被执行的一个任务，并尝试再次提交当前任务。
ThreadPoolExecutor.DiscardPolicy()：该策略默默地丢弃无法处理的任务，不予任何处理。如果允许任务丢失，这是最好的一种方案。
以上内置拒绝策略均实现了 RejectedExecutionHandler 接口，若以上策略仍无法满足实际 需要，完全可以自己扩展 RejectedExecutionHandler 接口。
5.2.4 创建一个ThreadPoolExecutor

int  corePoolSize  =    5;
int  maxPoolSize   =   10;
long keepAliveTime = 5000;
 
ExecutorService threadPoolExecutor =
    new ThreadPoolExecutor(
            corePoolSize,
            maxPoolSize,
            keepAliveTime,
            TimeUnit.MILLISECONDS,
                new LinkedBlockingQueue<Runnable>()
            );
6、ScheduledThreadPoolExecutor
ScheduledThreadPoolExecutor是ExecutorService的另一个实现类，从上面Java线程池ExecutorService继承树这幅图可以看出，ScheduledThreadPoolExecutor直接继承自ScheduledExecutorService，ScheduledThreadPoolExecutor 类的功能也主要体现在ScheduledExecutorService 接口上，而所以在介绍ScheduledThreadPoolExecutor之前先介绍一下ScheduledExecutorService接口。

6.1 ScheduledExecutorService接口介绍
java.util.concurrent.ScheduledExecutorService接口继承了ExecutorService，它的最主要的功能就是可以对其中的任务进行调度，比如延迟执行、定时执行等等。

ScheduledExecutorService接口定义：

public interface ScheduledExecutorService extends ExecutorService {
 
    public ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit);
 
    public ScheduledFuture<?> schedule(Callable task, long delay, TimeUnit timeunit);
 
    public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,long initialDelay, long period, TimeUnit unit);
 
    public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command,long initialDelay, long delay,TimeUnit unit);
 
}
6.1.1 schedule (Runnable task, long delay, TimeUnit timeunit)
这个方法的意思是在指定延迟之后运行task。这个方法有个问题，就是没有办法获知task的执行结果。如果我们想获得task的执行结果，我们可以传入一个Callable的实例（后面会介绍）。
 

ScheduledExecutorService scheduledExecutorService =
    Executors.newScheduledThreadPool(5);
 
ScheduledFuture scheduledFuture =
scheduledExecutorService.schedule(new Callable() {
    public Object call() throws Exception {
        System.out.println("Executed!");
        return "Called!";
    }
},5,TimeUnit.SECONDS);
System.out.println("result = " + scheduledFuture.get());
scheduledExecutorService.shutdown();
6.1.2 schedule (Callable task, long delay, TimeUnit timeunit)

这个方法与schedule (Runnable task)类似，也是在指定延迟之后运行task，不过它接收的是一个Callable实例，此方法会返回一个ScheduleFuture对象，通过ScheduleFuture我们可以取消一个未执行的task，也可以获得这个task的执行结果。

ScheduledExecutorService scheduledExecutorService =
    Executors.newScheduledThreadPool(5);
 
ScheduledFuture scheduledFuture =
scheduledExecutorService.schedule(new Callable() {
    public Object call() throws Exception {
        System.out.println("Executed!");
        return "Called!";
    }
},5,TimeUnit.SECONDS);
 
System.out.println("result = " + scheduledFuture.get());
scheduledExecutorService.shutdown();
6.1.3 scheduleAtFixedRate (Runnable, long initialDelay, long period, TimeUnit timeunit)
这个方法的作用是周期性的调度task执行。task第一次执行的延迟根据initialDelay参数确定，以后每一次执行都间隔period时长。

如果task的执行时间大于定义的period，那么下一个线程将在当前线程完成之后再执行。整个调度保证不会出现一个以上任务同时执行。

6.1.4 scheduleWithFixedDelay (Runnable, long initialDelay, long period, TimeUnit timeunit)
scheduleWithFixedDelay的参数和scheduleAtFixedRate参数完全一致，它们的不同之处在于对period调度周期的解释。

在scheduleAtFixedRate中，period指的两个任务开始执行的时间间隔，也就是当前任务的开始执行时间和下个任务的开始执行时间之间的间隔。

而在scheduleWithFixedDelay中，period指的当前任务的结束执行时间到下个任务的开始执行时间。

6.1.5 ScheduledExecutorService的关闭
和ExecutorService类似, 我们在使用完ScheduledExecutorService时需要关闭它。如果不关闭的话，JVM会一直运行直，即使所有线程已经关闭了。

关闭ScheduledExecutorService可以使用其继承自ExecutorService接口的shutdown()和shutdownNow()方法。

6.2 ScheduledThreadPoolExecutor
ScheduledThreadPoolExecutor继承自ThreadPoolExecutor，构造参数很简单，只有3个：

1. int corePoolSize：线程池维护线程的最少数量
2. ThreadFactory threadFactory：线程工程类，线程池用它来制造线程
3. RejectedExecutionHandler handler：线程池对拒绝任务的处理策略
具体使用方法请参考上方ThreadPoolExecutor或者使用Executors。

7、Executors
创建一个什么样的ExecutorService的实例（即线程池）需要我们的具体应用场景而定，不过Java给我们提供了一个Executors工厂类，它可以帮助我们很方便的创建各种类型ExecutorService线程池，Executors一共可以创建下面这四类线程池：

newCachedThreadPool 创建一个可缓存线程池，如果线程池长度超过处理需要，可灵活回收空闲线程，若无可回收，则新建线程。
newFixedThreadPool 创建一个定长线程池，可控制线程最大并发数，超出的线程会在队列中等待。
newScheduledThreadPool 创建一个定长线程池，支持定时及周期性任务执行。
newSingleThreadExecutor 创建一个单线程化的线程池，它只会用唯一的工作线程来执行任务，保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。
备注：Executors只是一个工厂类，它所有的方法返回的都是ThreadPoolExecutor、ScheduledThreadPoolExecutor这两个类的实例。


public class ThreadPoolExecutor extends AbstractExecutorService {
public class ForkJoinPool extends AbstractExecutorService {
public class ThreadPoolExecutor extends AbstractExecutorService {

public abstract class AbstractExecutorService implements ExecutorService {


使用线程池
Java语言虽然内置了多线程支持，启动一个新线程非常方便，但是，创建线程需要操作系统资源（线程资源，栈空间等），频繁创建和销毁大量线程需要消耗大量时间。

如果可以复用一组线程：

┌─────┐ execute  ┌──────────────────┐
│Task1│─────────>│ThreadPool        │
├─────┤          │┌───────┐┌───────┐│
│Task2│          ││Thread1││Thread2││
├─────┤          │└───────┘└───────┘│
│Task3│          │┌───────┐┌───────┐│
├─────┤          ││Thread3││Thread4││
│Task4│          │└───────┘└───────┘│
├─────┤          └──────────────────┘
│Task5│
├─────┤
│Task6│
└─────┘
  ...
那么我们就可以把很多小任务让一组线程来执行，而不是一个任务对应一个新线程。这种能接收大量小任务并进行分发处理的就是线程池。

简单地说，线程池内部维护了若干个线程，没有任务的时候，这些线程都处于等待状态。如果有新任务，就分配一个空闲线程执行。如果所有线
程都处于忙碌状态，新任务要么放入队列等待，要么增加一个新线程进行处理。

Java标准库提供了ExecutorService接口表示线程池，它的典型用法如下：
创建一个 ExecutorService ，可以使用 Executors 工厂方法来创建一个 ExecutorService 实例。
// 创建固定大小的线程池:
ExecutorService executor = Executors.newFixedThreadPool(3);
// 提交任务:
executor.submit(task1);
executor.submit(task2);
executor.submit(task3);
executor.submit(task4);
executor.submit(task5);
因为ExecutorService只是接口，Java标准库提供的几个常用实现类有：

-FixedThreadPool：线程数固定的线程池；
-CachedThreadPool：线程数根据任务动态调整的线程池；
-SingleThreadExecutor：仅单线程执行的线程池。
创建这些线程池的方法都被封装到Executors这个类中。我们以FixedThreadPool为例，看看线程池的执行逻辑：
*/
// thread-pool
import java.util.concurrent.*;

public class 使用线程池 {
    public static void main(String[] args) {
        // 创建一个固定大小的线程池:
        ExecutorService es = Executors.newFixedThreadPool(4);
        //ExecutorService es = Executors.newCachedThreadPool();
        for (int i = 0; i < 6; i++) {
            es.submit(new Taskn("" + i));//int i-->String i
        }
        // 关闭线程池:
        es.shutdown();
    }
}

class Taskn implements Runnable {
    private final String name;

    public Taskn(String name) {
        this.name = name;
    }

    @Override
    public void run() {
        System.out.println("start task " + name);
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
        }
        System.out.println("end task " + name);
    }
}

//我们观察执行结果，一次性放入6个任务，由于线程池只有固定的4个线程，因此，前4个任务会同时执行，等到有线程空闲后，才会执行后面的
//两个任务。
//
//线程池在程序结束的时候要关闭。使用shutdown()方法关闭线程池的时候，它会等待正在执行的任务先完成，然后再关闭。shutdownNow()会
//立刻停止正在执行的任务，awaitTermination()则会等待指定的时间让线程池关闭。
//
//如果我们把线程池改为CachedThreadPool，由于这个线程池的实现会根据任务数量动态调整线程池的大小，所以6个任务可一次性全部同时执行。
//
//如果我们想把线程池的大小限制在4～10个之间动态调整怎么办？我们查看Executors.newCachedThreadPool()方法的源码：
//
//public static ExecutorService newCachedThreadPool() {
//    return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
//                                    60L, TimeUnit.SECONDS,
//                                    new SynchronousQueue<Runnable>());
//}
//因此，想创建指定动态范围的线程池，可以这么写：
//
//int min = 4;
//int max = 10;
//ExecutorService es = new ThreadPoolExecutor(min, max,
//        60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>());
//ScheduledThreadPool
//还有一种任务，需要定期反复执行，例如，每秒刷新证券价格。这种任务本身固定，需要反复执行的，可以使用ScheduledThreadPool。放
//入ScheduledThreadPool的任务可以定期反复执行。
//
//创建一个ScheduledThreadPool仍然是通过Executors类：
//
//ScheduledExecutorService ses = Executors.newScheduledThreadPool(4);
//我们可以提交一次性任务，它会在指定延迟后只执行一次：
//
//// 1秒后执行一次性任务:
//ses.schedule(new Task("one-time"), 1, TimeUnit.SECONDS);
//如果任务以固定的每3秒执行，我们可以这样写：
//
//// 2秒后开始执行定时任务，每3秒执行:
//ses.scheduleAtFixedRate(new Task("fixed-rate"), 2, 3, TimeUnit.SECONDS);

//如果任务以固定的3秒为间隔执行，我们可以这样写：
//
//// 2秒后开始执行定时任务，以3秒为间隔执行:
//ses.scheduleWithFixedDelay(new Task("fixed-delay"), 2, 3, TimeUnit.SECONDS);
//注意FixedRate和FixedDelay的区别。FixedRate是指任务总是以固定时间间隔触发，不管任务执行多长时间：
//
//│░░░░   │░░░░░░ │░░░    │░░░░░  │░░░  
//├───────┼───────┼───────┼───────┼────>
//│<─────>│<─────>│<─────>│<─────>│
//而FixedDelay是指，上一次任务执行完毕后，等待固定的时间间隔，再执行下一次任务：
//
//│░░░│       │░░░░░│       │░░│       │░
//└───┼───────┼─────┼───────┼──┼───────┼──>
//    │<─────>│     │<─────>│  │<─────>│
//因此，使用ScheduledThreadPool时，我们要根据需要选择执行一次、FixedRate执行还是FixedDelay执行。
//
//细心的童鞋还可以思考下面的问题：
//
//在FixedRate模式下，假设每秒触发，如果某次任务执行时间超过1秒，后续任务会不会并发执行？
//
//如果任务抛出了异常，后续任务是否继续执行？
//
//Java标准库还提供了一个java.util.Timer类，这个类也可以定期执行任务，但是，一个Timer会对应一个Thread，所以，一个Timer只能定期执行
//一个任务，多个定时任务必须启动多个Timer，而一个ScheduledThreadPool就可以调度多个定时任务，所以，我们完全可以用ScheduledThreadPool
//取代旧的Timer。
//
//练习
//从下载练习：使用线程池 （推荐使用IDE练习插件快速下载）
//
//小结
//JDK提供了ExecutorService实现了线程池功能：
//
//线程池内部维护一组线程，可以高效执行大量小任务；
//
//Executors提供了静态方法创建不同类型的ExecutorService；
//
//必须调用shutdown()关闭ExecutorService；
//
//ScheduledThreadPool可以定期调度多个任务。
//

//使用原因
//
//经常创建和销毁线程，对性能的影响很大
//可以根据系统的需求和硬件环境灵活的控制线程的数量，且可以对所有线程进行统一的管理和控制，从而提高系统的运行效率，降低系统运行压力
//思路
//
//提前创建好多个线程放入线程池中，使用时直接获取，使用完放回池中，可以避免频繁创建、销毁，从而实现重复利用
//线程池其实就是一种多线程处理形式，处理过程中可以将任务添加到任务队列中，然后在创建线程后自动启动这些任务
//
//二、参数介绍
//通过观察 java 中 ThreadPoolExecutor 的构造函数学习线程池的七个参数

//                    ┌───────────┐
//                    │  Executor │
//                    └───────────┘
//                          ▲
//                          │
//                  ┌───────────────┐
//                  │ExecutorService│
//                  └───────────────┘
//                     ▲         ▲
//            ┌────────┘         └─────────┐
//            │                            │
//┌───────────────────────┐    ┌────────────────────────┐
//│AbstractExecutorService│    │ScheduledExecutorService│
//└───────────────────────┘    └────────────────────────┘
//            ▲                           ▲
//            │                           ┊
//   ┌──────────────────┐                 ┊
//   │ThreadPoolExecutor│                 ┊
//   └──────────────────┘                 ┊
//            ▲                           ┊
//            └─────┐          ┌┄┄┄┄┄┄┄┄┄┄┘
//                  │          ┊
//           ┌───────────────────────────┐
//           │ScheduledThreadPoolExecutor│
//           └───────────────────────────┘


//◆举一个生活中的例子理解上述参数
//
// ▪a客户(任务)去银行(线程池)办理业务，但银行刚开始营业，窗口服务员还未就位(相当于线程池中初始线程数量为0)
// ▪于是经理(线程池管理者)就安排1号工作人员(创建1号线程执行任务)接待a客户
// ▪在a客户业务还没办完时，b客户(任务)又来了，于是经理(线程池管理者)就安排2号工作人员(创建2号线程执行任务)接待b客户(又创建了一个新的线程)；假设该银行总共就2个窗口(核心线程数量是2)
// ▪紧接着在a,b客户都没有结束的情况下c客户来了，于是经理(线程池管理者)就安排c客户先坐到银行大厅的座位上(座位相当于任务队列)等候；并告知他：如果1、2号工作人员空出，c就可以前去办理业务
// ▪此时d客户又到了银行，工作人员都在忙，大厅座位也满了(核心线程无空闲，且任务队列已满)于是经理赶紧安排临时工(新创建的临时线程)在大堂站着，手持pad设备给d客户办理业务
// ▪假如前面的业务都没有结束的时候e客户又来了，此时正式工作人员都上了，临时工也上了，座位也满了(临时工加正式员工的总数量就是最大线程数，值为3)
// ▪于是经理只能按《超出银行最大接待能力处理办法》(拒绝策略)处理e客户
// ▪最后，进来办业务的人少了，大厅的临时工空闲时间也超过了1个小时(最大空闲时间)，经理就会让这位空闲的临时工下班(销毁线程)
// ▪但是为了保证银行正常工作(有一个allowCoreThreadTimeout变量控制是否允许销毁核心线程，默认false)，即使正式工闲着，也不得提前下班，所以1、2号工作人员继续待着(池内保留所有核心线程，默认不销毁核心线程，仅销毁达到最大空闲时间的临时线程)
//
//◆添加一个任务的流程图

//┌───────────┐
//│   提交任务  │
//└───────────┘
//      │
//      ▼
//┌───────────┐           ┌───────────┐
//│   核心线程  │ 否     　  │    　　　　 │  
//│   达到最大  │──────────→│   执行任务  │  
//│     ？  　 │           │   　　　　  │  
//└───────────┘           └───────────┘
//   是　│
//      ▼
//┌───────────┐           ┌───────────┐
//│   任务队列  │ 否    　   │ 将任务添加到 │  
//│   已　　满  │──────────→│ 任务队列等待 │  
//│   ？　　　  │           │    执行    │  
//└───────────┘           └───────────┘
//   是　│
//      ▼
//┌───────────┐           ┌───────────┐
//│   线程数达  │ 否       　│   创建非核  │  
//│   到最大线  │──────────→│   心线程执  │  
//│   程数？  　│           │   行任务　  │  
//└───────────┘           └───────────┘
//   是　│
//      ▼
//┌───────────┐
//│   执行饱和  │
//│   策　　略  │
//└───────────┘


//注意：
//
//  ▪任务队列满了之后，才会创建非核心线程（临时线程）
//  ▪核心线程并不是一开始就有，当提交任务时才会创建核心线程
//
//  三、ExecutorService接口的介绍
//  使用 ExecutorService 接口可以管理线程池，比如提交任务，停止任务
//  1. 接口中常用方法
//  ◆void shutdown() 当任务队列中的所有任务都执行完成之后，销毁线程池 (不允许有新的任务提交)
//  　▪正在运行的任务不会受到影响，继续运行
//  　▪shutdown() 之后提交的任务会抛出 RejectedExecutionException 异常，代表拒绝接收
//  ◆List<Runnable> shutdownNow() (可能会) 停止正在执行的任务，暂停处理正在等待的任务，并返回等待执行的任务列表
//  　▪shutdownNow() 之后提交的任务会抛出RejectedExecutionException 异常，代表拒绝接收
//  　▪对于正在运行的任务
//  　　▪如果此任务的代码可以抛出 InterruptedException 异常 (如wait、sleep、join方法等)，则停止此任务，抛出 InterruptedException 异常
//  　　▪如果此任务的代码中无法抛出 InterruptedException 异常，则此任务会持续运行直到结束
//  ◆<T> Future<T> submit(Callable<T> task) 提交带返回值的任务，返回一个表示该任务的 Future 对象
//
//  ◆Future<?> submit(Runnable task) 提交 Runnable 任务，并返回一个表示该任务的 Future 对象
//
//  ◆<T> Future<T> submit(Runnable task, T result) 提交 Runnable 任务，并返回一个表示该任务的 Future 对象
//
//  注意：Executor 接口中有 execute(Runnable task) 方法，可以用来提交 Runnable 任务
//
//  ◆其余方法:
//   提交tasks中所有任务
//　　<T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
//    throws InterruptedException;

//   提交tasks中所有任务,带超时时间。
//   <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks,
//       long timeout, TimeUnit unit) throws InterruptedException;

//   提交tasks中所有任务，哪个任务先成功执行完毕，返回此任务执行结果，其他任务取消。
//   <T> T invokeAny(Collection<? extends Callable<T>> tasks)
//      throws InterruptedException, ExecutionException;

//   提交tasks中所有任务，哪个任务先成功执行完毕，返回此任务执行结果，其他任务取消，带超时时间。
//   <T> T invokeAny(Collection<? extends Callable<T>> tasks,
//        long timeout, TimeUnit unit)
//   throws InterruptedException, ExecutionException, TimeoutException;
//
//
//  2. 获取接口实例
//  ◆获取 ExecutorService 实例可以利用 JDK 中的 Executors 类中的静态方法，常用的如下
//
//    ▪带缓存线程池 static ExecutorService newCachedThreadPool()
//
//    ▪固定大小线程池 static ExecutorService newFixedThreadPool(int nThreads)
//
//    ▪单线程线程池 static ExecutorService newSingleThreadExecutor()
//
//  注意：上述三者都有包含 ThreadFactory threadFactory 的参数的重载方法
//
//  四、带缓存线程池
//  ◆使用方法 ExecutorService executorService = Executors.newCachedThreadPool();
//
//  ◆newCachedThreadPool 方法详情
//
//  public static ExecutorService newCachedThreadPool() {
//      return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
//                                    60L, TimeUnit.SECONDS,
//                                    new SynchronousQueue<Runnable>());
//  }
// 
//  ◆特点
//
//    ▪核心线程数为0，所有线程都是临时线程，线程可重复利用
//    ▪最大线程数为 Integer.MAX_VALUE ，表示 Java 中的最大整数，意味着线程可以无限创建
//    ▪临时线程的最大空闲时间是60s
//    ▪任务队列（阻塞队列）的方式为没有容量，来一个任务使用一个线程执行它，任务不会等待
//    ▪适合任务数密集，但每个任务执行时间较短的情况
//  ◆由于每个线程执行完之后会归还池中，在空闲时间内还可以执行其余任务，故起名为带缓存
//
//  代码实现
//
//  情况一：
//
//  public class CachedThreadPoolTest {
//  	public static void main(String[] args) {
//          //获取 ExecutorService 实例可以利用 JDK 中的 Executors 类中的静态方法
//  		ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
//
//  		//提交10个任务给线程池，每个任务输出自己的索引
//  		for (int i = 0; i < 10; i++) {
//  			Runnable task = new Runnable() {
//  				public void run() {
//  					try {
//  						Thread.sleep(1000);
//  					} catch (InterruptedException e) {
//  						e.printStackTrace();
//  					}
//  					System.out.println(Thread.currentThread().getName()+">>"+index);
//  				}
//  			};
//  			// 提交任务
//  			cachedThreadPool.execute(task);
//  		}
//          //关闭线程池
//  		cachedThreadPool.shutdown();
//  	}
//  }
//  
//  运行结果：
//
//  情况二：
//
//  public class CachedThreadPoolTest {
//  	public static void main(String[] args) {
//
//  		ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
//
//  		//提交10个任务给线程池，每个任务输出自己的索引
//  		for (int i = 0; i < 10; i++) {
//  			final int index = i;
//  			try {
//  				Thread.sleep(1000);
//  			} catch (InterruptedException e) {
//  				e.printStackTrace();
//  			}
//  			Runnable task = new Runnable() {
//  				public void run() {
//  					System.out.println(Thread.currentThread().getName()+">>"+index);
//  				}
//  			};
//  			// 提交任务
//  			cachedThreadPool.execute(task);
//  		}
//          //关闭线程池
//  		cachedThreadPool.shutdown();
//  	}
//  }
//  
//  运行结果：
//
//  五、固定大小线程池
//  ◆使用方法 ExecutorService fixedThreadPool = Executors.newFixedThreadPool(n);
//
//    ▪参数指定 核心线程数 和 最大线程数 的大小
//  ◆newFixedThreadPool 方法详情
//
//  public static ExecutorService newFixedThreadPool(int nThreads) {
//      return new ThreadPoolExecutor(nThreads, nThreads,
//                                    0L, TimeUnit.MILLISECONDS,
//                                    new LinkedBlockingQueue<Runnable>());
//  }
// 
//  ◆特点
//
//    ▪核心线程数 == 最大线程数，也就是说没有临时线程
//    ▪无需设置临时线程的最大空闲时间
//    ▪阻塞队列是无界的，可以存放任意数量的任务
//    ▪适用于任务量已知，且相对耗时的任务（推荐使用）
//  代码实现
//
//  public class FixedThreadPoolTest {
//  	public static void main(String[] args) {
//
//  		ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
//
//  		// 向线程池提交9个任务，每个任务输出对应的索引
//  		for (int i = 0; i < 9; i++) {
//  			final int index = i;
//  			fixedThreadPool.execute(new Runnable() {
//  				public void run() {
//  					try {
//  						System.out.println(Thread.currentThread().getName()+">>"+index);
//  						Thread.sleep(1000);
//  					} catch (InterruptedException e) {
//  						e.printStackTrace();
//  					}
//  				}
//  			});
//  		}
//          //关闭线程池
//  		fixedThreadPool.shutdown();
//  	}
//  }
//  
//  运行结果：
//pool-1-thread-2>>1
//pool-1-thread-3>>2
//pool-1-thread-1>>0
//pool-1-thread-3>>3
//pool-1-thread-2>>4
//pool-1-thread-1>>5
//pool-1-thread-3>>6
//pool-1-thread-2>>7
//pool-1-thread-1>>8
//
//  六、单线程线程池
//  ◆使用方法 ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
//
//  ◆newSingleThreadExecutor 方法详情
//
//  public static ExecutorService newSingleThreadExecutor() {
//      return new FinalizableDelegatedExecutorService
//          (new ThreadPoolExecutor(1, 1,
//                                  0L, TimeUnit.MILLISECONDS,
//                                  new LinkedBlockingQueue<Runnable>()));
//  }
// 
//  ◆特点
//
//    ▪核心线程数和最大线程数都是1，没有临时线程
//    ▪无需设置临时线程的最大空闲时间
//    ▪阻塞队列是无界的，可以存放任意数量的任务
//    ▪适用于希望多个任务排队执行的情况
//  ◆与自己定义一个线程执行任务的区别
//
//    ▪如果自定义的线程出现错误，则程序会终止，队列中的任务都无法执行；而线程池如果当前线程出现错误，还会新建一个线程，保证任务的正常执行
//  代码实现
//
//  public class SingleThreadExecutorTest {
//  	public static void main(String[] args) {
//  		
//  		ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
//  		
//  		//提交5个任务给线程池
//  		for (int i = 0; i < 10; i++) {
//  			final int index = i;
//  			Runnable task = new Runnable() {
//  				public void run() {
//  					try {
//  						System.out.println(Thread.currentThread().getName()+index);
//  						Thread.sleep(1000);
//  					} catch (InterruptedException e) {
//  						e.printStackTrace();
//  					}
//  				}
//  			};
//  			//提交任务
//  			singleThreadExecutor.execute(task);
//  		}
//  		//关闭线程池
//  		singleThreadExecutor.shutdown();
//  	}
//  }
//  
//  运行结果：同一个线程按顺序执行5个任务
//
//
//  七、ScheduledExecutorService接口的介绍
//  ◆ScheduledExecutorService 继承 ExecutorService 接口，具备了延迟运行或定期执行任务的能力
//  1. 接口中常用方法
//  ◆<V> ScheduledFuture<V> schedule(Callable<V> callable, long delay, TimeUnit unit)
//    ▪延迟时间单位是unit，延迟delay时间后执行callable
//  ◆ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit)
//    ▪延迟时间单位是unit，延迟delay时间后执行command
//  ◆ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit)
//    ▪延迟时间单位是unit，延迟initialDelay时间后首次执行，每间隔period时间重复执行一次command
//  ◆ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit)
//    ▪延迟时间单位是unit，延迟initialDelay时间后首次执行，每次任务执行完成之后，再等待delay时间后执行下一次任务
//  2. 获取接口实例
//  ◆获取 ScheduledExecutorService 实例可以利用 JDK 中的 Executors 类中的静态方法，常用的如下
//
//    ▪static ScheduledExecutorService newScheduledThreadPool(int corePoolSize)
//      ▪创建一个可重用固定线程数的线程池且允许延迟运行或定期执行任务
//    ▪static ScheduledExecutorService newSingleThreadScheduledExecutor()
//      ▪创建一个单线程执行程序，它允许在给定延迟后运行命令或者定期执行任务
//  注意：上述二者都有包含 ThreadFactory threadFactory 的参数的重载方法
//
//  八、时间调度线程池
//  ◆使用方法 ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(n);
//
//    ▪参数指定核心线程数
//  ◆newScheduledThreadPool 方法详情
//
//  public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
//      return new ScheduledThreadPoolExecutor(corePoolSize);
//  }
//
//  //ScheduledThreadPoolExecutor继承了ThreadPoolExecutor
//
//  public ScheduledThreadPoolExecutor(int corePoolSize) {
//      super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
//            new DelayedWorkQueue());
//  }
//  
//  ◆特点
//
//    ▪参数指定核心线程数
//    ▪最大线程数为 “无限大”
//    ▪阻塞队列的方式是具有延迟特性的无界阻塞队列
//    ▪由于 DelayedWorkQueue 队列属于无界队列，故不会产生临时线程
//  代码实现
//
//  情况一：schedule 方法
//
//  ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(1);
//
//  //提交10个任务至线程池
//  for (int i = 0; i < 10; i++) {
//      final int index = i;
//      Runnable task = new Runnable() {
//          public void run() {
//              System.out.println(new Date().toString()
//                    + " 第 " + (index + 1) + " 个任务延迟了 " + index + " 秒才运行");
//          }
//      };
//
//      //第一个任务延迟1秒执行，第二个任务延迟2秒执行，第三个任务延迟3秒执行...
//      //会立马将所有任务提交，主线程向下运行，提交之后到底什么时候执行，取决于设定值
//      ScheduledFuture<?> schedule = scheduledThreadPool.schedule(task, i, TimeUnit.SECONDS);
//  }
//
//  //ScheduledExecutorService继承ExecutorService，故可调用父接口方法
//  //执行完所有任务后，关闭线程池
//  scheduledThreadPool.shutdown();
//  
//  运行结果：
//
//
//
//  情况二：scheduleAtFixedRate 方法
//
//  ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
//
//  //创建任务，每隔一秒执行一次，但每次任务执行时间需要三秒
//  Runnable task = new Runnable() {
//      public void run() {
//          try {
//              System.out.println(new Date().toString() + " " +
//                                 Thread.currentThread().getName() + " 任务执行了！");
//              Thread.sleep(3000);
//          } catch (InterruptedException e) {
//              e.printStackTrace();
//          }
//      }
//  };
//  scheduledThreadPool.scheduleAtFixedRate(task, 0, 1, TimeUnit.SECONDS);
//  
//  运行结果：
//
//
//
//  出现原因：
//
//  任务的执行时间超过了任务的间隔时间，下一次任务达到了间隔时间准备执行时，发现上一次任务还没有结束，必须等待，当上一次任务执行结束之后，立即启动处于等待状态的下一次任务，所以没有按照设定的间隔时间执行任务
//
//  情况三：scheduleWithFixedDelay 方法
//
//  ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
//
//  //创建任务，一个任务要执行2秒，执行完成之后，再等待1秒开启下一个任务
//  Runnable task = new Runnable() {
//      public void run() {
//          try {
//              System.out.println(new Date().toString() + " " +
//                                 Thread.currentThread().getName() + " 任务执行了！");
//              Thread.sleep(2000);
//          } catch (InterruptedException e) {
//              e.printStackTrace();
//          }
//      }
//  };
//  scheduledThreadPool.scheduleWithFixedDelay(task, 0, 1, TimeUnit.SECONDS);
//  
//  运行结果：
//
//
//
//  九、拒绝策略
//  Java 中提供了四种内置的拒绝策略
//
//
//
//  RejectedExecutionHandler 源码
//
//  public interface RejectedExecutionHandler {
//      void rejectedExecution(Runnable r, ThreadPoolExecutor executor);
//  }
//  
//  1. AbortPolicy
//  默认的拒绝策略
//
//  任务无法处理时会抛出异常 RejectedExecutionException，不再执行这个任务
//
//  源码
//
//  public static class AbortPolicy implements RejectedExecutionHandler {
//
//      public AbortPolicy() { }
//
//      //重写的方法
//      public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
//          throw new RejectedExecutionException("Task " + r.toString() +
//                          " rejected from " + e.toString());
//      }
//  }
//  
//  2. CallerRunsPolicy
//  如果线程池没有shutdown，则调用 execute 函数的上层线程(main线程)去执行被拒绝的任务
//
//  源码
//
//  public static class CallerRunsPolicy implements RejectedExecutionHandler {
//
//      public CallerRunsPolicy() { }
//
//      public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
//          if (!e.isShutdown()) {
//              r.run();
//          }
//      }
//  }
//  
//  3. DiscardOldestPolicy
//  将任务队列中最老的任务丢弃(快要被执行的任务)，尝试再次提交新任务
//
//  源码
//
//  public static class DiscardOldestPolicy implements RejectedExecutionHandler {
//
//      public DiscardOldestPolicy() { }
//
//      public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
//          if (!e.isShutdown()) {
//              e.getQueue().poll();
//              e.execute(r);
//          }
//      }
//  }
//  
//  4. DiscardPolicy
//  直接丢弃这个无法被处理的任务
//
//  源码
//
//  public static class DiscardPolicy implements RejectedExecutionHandler {
//
//      public DiscardPolicy() { }
//
//      public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
//          //没有做处理表示直接丢弃这个任务
//      }
//  }
//  
//  5. 自定义拒绝策略
//  观察上述四种拒绝策略的源码，得知自定义拒绝策略有如下步骤
//
//  自定义策略类实现 RejectedExecutionHandler 接口
//  重写接口中的 rejectedExecution 方法
//  示例
//
//  class MyPolicy implements RejectedExecutionHandler{
//      
//      public MyPolicy() { }
//      
//  	@Override
//  	public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
//  		System.out.println(r + "被拒绝执行");
//  		//对于无法处理的任务，仅输出了一句话，直接丢弃此任务
//  	}
//  }
//  
//  十、自定义线程池
//  观察上述四种线程池的源码得知自定义的线程池需要 new ThreadPoolExecutor，定义各项参数的值
//
//  示例
//
//  /**
//   * 自定义线程池
//   * 1. 核心线程数为3，最大线程数为3
//   * 2. 由于没有临时线程，故不设置临时线程的空闲时间
//   * 3. 阻塞队列最多可以放1个任务
//   * 4. 拒绝策略为内置的AbortPolicy，会抛出异常
//   * 5. 最大同时容纳任务数为4个
//   * 6. 此处没有使用线程工厂
//   */
//  ThreadPoolExecutor executor = new ThreadPoolExecutor(3, 3, 0, TimeUnit.SECONDS,
//                                                       new LinkedBlockingQueue<Runnable>(1), new ThreadPoolExecutor.AbortPolicy());
//
//  //提交8个任务，每个任务的执行时间为1秒
//  for(int i = 1; i < 9; i++){
//      int index = i;
//      executor.submit(new Runnable() {
//          @Override
//          public void run() {
//              System.out.println(Thread.currentThread().getName() +
//                                 " 执行了第 " + index + " 个任务");
//              try {
//                  Thread.sleep(1000);
//              } catch (InterruptedException e) {
//                  e.printStackTrace();
//              }
//          }
//      });
//  }
//  //关闭线程池
//  executor.shutdown();
//
//  //多出了4个无法处理的任务，故一定会抛出异常
//  
//  运行结果：
//
//
//
//  十一、ThreadFactory
//  当有任务提交到线程池时，会创建线程执行任务(一开始并没有核心线程)
//
//  可以使用 ThreadFactory 改变线程创建时的行为，比如修改线程的名字、打印日志等
//
//  ThreadFactory 源码
//
//  public interface ThreadFactory {
//      Thread newThread(Runnable r);
//  }
// 
//  使用步骤
//
//  创建一个类实现 ThreadFactory 接口
//  重写 newThread 方法，参数传递 Runnable 实例，返回 Thread 实例
//  示例
//
//  //定义线程工厂
//  class DemoThreadFactory implements ThreadFactory {
//
//      public Thread newThread(Runnable r) {
//
//          // 1.输出日志
//          System.out.println("当前时间是：" + new Date().toString());
//
//          // 2.自定义线程名字
//          Thread thread = new Thread(r);
//          thread.setName("高奇泽的线程" + thread.getId());
//          System.out.println("新建的线程的名字是：" + thread.getName());
//          
//          return thread;
//      }
//  }
//
//  //使用线程工厂
//  public class ThreadPoolExecutorTest {
//
//  	public static void main(String[] args) {
//
//  		// 自定义线程池
//  		// 使用线程工厂
//  		ThreadPoolExecutor executor = new ThreadPoolExecutor(3, 3, 0, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(1), new DemoThreadFactory());
//
//  		//提交4个任务，每个任务的执行时间为1秒
//  		for(int i = 0; i < 4; i++){
//  			executor.submit(new Runnable() {
//  				@Override
//  				public void run() {
//  					try {
//  						Thread.sleep(1000);
//  					} catch (InterruptedException e) {
//  						e.printStackTrace();
//  					}
//  				}
//  			});
//  		}
//  		//关闭线程池
//  		executor.shutdown();
//  	}
//  }
//  
//  运行结果：
//
//  十二、线程池常用方法
//  1. 线程池结束状态判断
//  isShutdown() 用来判断线程池是否已经关闭
//
//  调用 shutdownNow 和 shutdown 方法，isShutdown 会返回 true（即使还有任务正在运行）
//  isTerminated() 任务全部执行完毕，并且线程池已经关闭，才会返回 true
//
//  2. 核心线程预启动
//  默认情况下，核心线程只有在任务提交的时候才会创建
//  预启动策略，可以让核心线程提前启动，从而增强最初提交的任务运行性能
//  调用 ThreadPoolExecutor 类中的以下两个方法
//  prestartCoreThread() 启动1个核心线程
//  prestartAllCoreThreads() 启动所有核心线程
//  3. 线程和线程池切面编程
//  在线程执行前、执行后增加切面，在线程池关闭时执行某段程序
//  需要实现自己的线程池类，并覆写 beforeExecute、afterExecute、terminated 方法
//  4. 移除线程池中的任务
//  调用 ThreadPoolExecutor 类中的 remove() 方法
//  已经正在运行中的任务不可以删除
//  execute方法提交的，未运行的任务可以删除
//  submit方法提交的，未运行任务不可以删除
//  5. 获取线程池的各项数据
//  调用 ThreadPoolExecutor 类中的如下方法
//  返回核心线程数 getCorePoolSize
//  返回当前线程池中的线程数 getPoolSize
//  返回最大允许的线程数 getMaximumPoolSize
//  返回池中同时存在的最大线程数 getLargestPoolSize
//  返回预定执行的任务总和 getTaskCount
//  返回当前线程池已经完成的任务数 getCompletedTaskCount
//  返回正在执行任务的线程的大致 数目 getActiveCount
//  返回线程池空闲时间 getKeepAliveTime
//  十三、异步计算结果Future
//  有时需要利用线程进行一些计算，然后获取这些计算的结果，可以通过 Future 对象获取线程计算的结果
//  Future 中的常用方法
//  boolean cancel(boolean mayInterruptIfRunning) 试图取消对此任务的执行，参数用来指定是否中断正在运行的任务
//  V get() 如有必要，等待计算完成，然后获取其结果（获取的是Callable接口中call方法的返回值）
//  V get(long timeout, TimeUnit unit) 如有必要，最多等待 timeout 时间获取结果
//  boolean isCancelled() 如果在任务正常完成前将其取消，则返回 true
//  boolean isDone() 如果任务已完成，则返回 true

/*
下面我们就对ThreadPoolExecutor的使用方法进行一个详细的概述。

首先看下ThreadPoolExecutor的构造函数

    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) {
        if (corePoolSize < 0 ||
            maximumPoolSize <= 0 ||
            maximumPoolSize < corePoolSize ||
            keepAliveTime < 0)
            throw new IllegalArgumentException();
        if (workQueue == null || threadFactory == null || handler == null)
            throw new NullPointerException();
        this.acc = System.getSecurityManager() == null ?
                null :
                AccessController.getContext();
        this.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.workQueue = workQueue;
        this.keepAliveTime = unit.toNanos(keepAliveTime);
        this.threadFactory = threadFactory;
        this.handler = handler;
    }
构造函数的参数含义如下：

corePoolSize:指定了线程池中的线程数量，它的数量决定了添加的任务是开辟新的线程去执行，还是放到workQueue任务队列中去；

maximumPoolSize:指定了线程池中的最大线程数量，这个参数会根据你使用的workQueue任务队列的类型，决定线程池会开辟的最大线程数量；

keepAliveTime:当线程池中空闲线程数量超过corePoolSize时，多余的线程会在多长时间内被销毁；

unit:keepAliveTime的单位

workQueue:任务队列，被添加到线程池中，但尚未被执行的任务；它一般分为直接提交队列、有界任务队列、无界任务队列、优先任务队列几种；

threadFactory:线程工厂，用于创建线程，一般用默认即可；

handler:拒绝策略；当任务太多来不及处理时，如何拒绝任务；

接下来我们对其中比较重要参数做进一步的了解：

一、workQueue任务队列

上面我们已经介绍过了，它一般分为直接提交队列、有界任务队列、无界任务队列、优先任务队列；

1、直接提交队列：设置为SynchronousQueue队列，SynchronousQueue是一个特殊的BlockingQueue，它没有容量，没执行一个插入操作就会阻塞，需要再执行一个删除操作才会被唤醒，反之每一个删除操作也都要等待对应的插入操作。

public class ThreadPool {
    private static ExecutorService pool;
    public static void main( String[] args )
    {
        //maximumPoolSize设置为2 ，拒绝策略为AbortPolic策略，直接抛出异常
        pool = new ThreadPoolExecutor(1, 2, 1000, TimeUnit.MILLISECONDS, new SynchronousQueue<Runnable>(),Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy());
        for(int i=0;i<3;i++) {
            pool.execute(new ThreadTask());
        }   
    }
}

public class ThreadTask implements Runnable{
    
    public ThreadTask() {
        
    }
    
    public void run() {
        System.out.println(Thread.currentThread().getName());
    }
}
输出结果为

pool-1-thread-1
pool-1-thread-2
Exception in thread "main" java.util.concurrent.RejectedExecutionException: Task com.hhxx.test.ThreadTask@55f96302 rejected from java.util.concurrent.ThreadPoolExecutor@3d4eac69[Running, pool size = 2, active threads = 0, queued tasks = 0, completed tasks = 2]
    at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor.reject(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor.execute(Unknown Source)
    at com.hhxx.test.ThreadPool.main(ThreadPool.java:17)

可以看到，当任务队列为SynchronousQueue，创建的线程数大于maximumPoolSize时，直接执行了拒绝策略抛出异常。

使用SynchronousQueue队列，提交的任务不会被保存，总是会马上提交执行。如果用于执行任务的线程数量小于maximumPoolSize，则尝试创建新的进程，如果达到maximumPoolSize设置的最大值，则根据你设置的handler执行拒绝策略。因此这种方式你提交的任务不会被缓存起来，而是会被马上执行，在这种情况下，你需要对你程序的并发量有个准确的评估，才能设置合适的maximumPoolSize数量，否则很容易就会执行拒绝策略；

2、有界的任务队列：有界的任务队列可以使用ArrayBlockingQueue实现，如下所示

pool = new ThreadPoolExecutor(1, 2, 1000, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(10),Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy());
使用ArrayBlockingQueue有界任务队列，若有新的任务需要执行时，线程池会创建新的线程，直到创建的线程数量达到corePoolSize时，则会将新的任务加入到等待队列中。若等待队列已满，即超过ArrayBlockingQueue初始化的容量，则继续创建线程，直到线程数量达到maximumPoolSize设置的最大线程数量，若大于maximumPoolSize，则执行拒绝策略。在这种情况下，线程数量的上限与有界任务队列的状态有直接关系，如果有界队列初始容量较大或者没有达到超负荷的状态，线程数将一直维持在corePoolSize以下，反之当任务队列已满时，则会以maximumPoolSize为最大线程数上限。

3、无界的任务队列：有界任务队列可以使用LinkedBlockingQueue实现，如下所示

pool = new ThreadPoolExecutor(1, 2, 1000, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(),Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy());
使用无界任务队列，线程池的任务队列可以无限制的添加新的任务，而线程池创建的最大线程数量就是你corePoolSize设置的数量，也就是说在这种情况下maximumPoolSize这个参数是无效的，哪怕你的任务队列中缓存了很多未执行的任务，当线程池的线程数达到corePoolSize后，就不会再增加了；若后续有新的任务加入，则直接进入队列等待，当使用这种任务队列模式时，一定要注意你任务提交与处理之间的协调与控制，不然会出现队列中的任务由于无法及时处理导致一直增长，直到最后资源耗尽的问题。

4、优先任务队列：优先任务队列通过PriorityBlockingQueue实现，下面我们通过一个例子演示下

public class ThreadPool {
    private static ExecutorService pool;
    public static void main( String[] args )
    {
        //优先任务队列
        pool = new ThreadPoolExecutor(1, 2, 1000, TimeUnit.MILLISECONDS, new PriorityBlockingQueue<Runnable>(),Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy());
          
        for(int i=0;i<20;i++) {
            pool.execute(new ThreadTask(i));
        }    
    }
}

public class ThreadTask implements Runnable,Comparable<ThreadTask>{
    
    private int priority;
    
    public int getPriority() {
        return priority;
    }

    public void setPriority(int priority) {
        this.priority = priority;
    }

    public ThreadTask() {
        
    }
    
    public ThreadTask(int priority) {
        this.priority = priority;
    }

    //当前对象和其他对象做比较，当前优先级大就返回-1，优先级小就返回1,值越小优先级越高
    public int compareTo(ThreadTask o) {
         return  this.priority>o.priority?-1:1;
    }
    
    public void run() {
        try {
            //让线程阻塞，使后续任务进入缓存队列
            Thread.sleep(1000);
            System.out.println("priority:"+this.priority+",ThreadName:"+Thread.currentThread().getName());
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    
    }
}
我们来看下执行的结果情况

priority:0,ThreadName:pool-1-thread-1
priority:9,ThreadName:pool-1-thread-1
priority:8,ThreadName:pool-1-thread-1
priority:7,ThreadName:pool-1-thread-1
priority:6,ThreadName:pool-1-thread-1
priority:5,ThreadName:pool-1-thread-1
priority:4,ThreadName:pool-1-thread-1
priority:3,ThreadName:pool-1-thread-1
priority:2,ThreadName:pool-1-thread-1
priority:1,ThreadName:pool-1-thread-1

大家可以看到除了第一个任务直接创建线程执行外，其他的任务都被放入了优先任务队列，按优先级进行了重新排列执行，且线程池的线程数一直为corePoolSize，也就是只有一个。

通过运行的代码我们可以看出PriorityBlockingQueue它其实是一个特殊的无界队列，它其中无论添加了多少个任务，线程池创建的线程数也不会超过corePoolSize的数量，只不过其他队列一般是按照先进先出的规则处理任务，而PriorityBlockingQueue队列可以自定义规则根据任务的优先级顺序先后执行。

二、拒绝策略

一般我们创建线程池时，为防止资源被耗尽，任务队列都会选择创建有界任务队列，但种模式下如果出现任务队列已满且线程池创建的线程数达到你设置的最大线程数时，这时就需要你指定ThreadPoolExecutor的RejectedExecutionHandler参数即合理的拒绝策略，来处理线程池"超载"的情况。ThreadPoolExecutor自带的拒绝策略如下：

1、AbortPolicy策略：该策略会直接抛出异常，阻止系统正常工作；

2、CallerRunsPolicy策略：如果线程池的线程数量达到上限，该策略会把任务队列中的任务放在调用者线程当中运行；

3、DiscardOledestPolicy策略：该策略会丢弃任务队列中最老的一个任务，也就是当前任务队列中最先被添加进去的，马上要被执行的那个任务，并尝试再次提交；

4、DiscardPolicy策略：该策略会默默丢弃无法处理的任务，不予任何处理。当然使用此策略，业务场景中需允许任务的丢失；

以上内置的策略均实现了RejectedExecutionHandler接口，当然你也可以自己扩展RejectedExecutionHandler接口，定义自己的拒绝策略，我们看下示例代码：

public class ThreadPool {
    private static ExecutorService pool;
    public static void main( String[] args )
    {
        //自定义拒绝策略
        pool = new ThreadPoolExecutor(1, 2, 1000, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(5),
                Executors.defaultThreadFactory(), new RejectedExecutionHandler() {
            public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
                System.out.println(r.toString()+"执行了拒绝策略");
                
            }
        });
          
        for(int i=0;i<10;i++) {
            pool.execute(new ThreadTask());
        }    
    }
}

public class ThreadTask implements Runnable{    
    public void run() {
        try {
            //让线程阻塞，使后续任务进入缓存队列
            Thread.sleep(1000);
            System.out.println("ThreadName:"+Thread.currentThread().getName());
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    
    }
}
输出结果：

com.hhxx.test.ThreadTask@33909752执行了拒绝策略
com.hhxx.test.ThreadTask@55f96302执行了拒绝策略
com.hhxx.test.ThreadTask@3d4eac69执行了拒绝策略
ThreadName:pool-1-thread-2
ThreadName:pool-1-thread-1
ThreadName:pool-1-thread-1
ThreadName:pool-1-thread-2
ThreadName:pool-1-thread-1
ThreadName:pool-1-thread-2
ThreadName:pool-1-thread-1

可以看到由于任务加了休眠阻塞，执行需要花费一定时间，导致会有一定的任务被丢弃，从而执行自定义的拒绝策略；

三、ThreadFactory自定义线程创建

 线程池中线程就是通过ThreadPoolExecutor中的ThreadFactory，线程工厂创建的。那么通过自定义ThreadFactory，可以按需要对线程池中创建的线程进行一些特殊的设置，如命名、优先级等，下面代码我们通过ThreadFactory对线程池中创建的线程进行记录与命名

public class ThreadPool {
    private static ExecutorService pool;
    public static void main( String[] args )
    {
        //自定义线程工厂
        pool = new ThreadPoolExecutor(2, 4, 1000, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(5),
                new ThreadFactory() {
            public Thread newThread(Runnable r) {
                System.out.println("线程"+r.hashCode()+"创建");
                //线程命名
                Thread th = new Thread(r,"threadPool"+r.hashCode());
                return th;
            }
        }, new ThreadPoolExecutor.CallerRunsPolicy());
          
        for(int i=0;i<10;i++) {
            pool.execute(new ThreadTask());
        }    
    }
}

public class ThreadTask implements Runnable{    
    public void run() {
        //输出执行线程的名称
        System.out.println("ThreadName:"+Thread.currentThread().getName());
    }
}

我们看下输出结果

线程118352462创建
线程1550089733创建
线程865113938创建
ThreadName:threadPool1550089733
ThreadName:threadPool118352462
线程1442407170创建
ThreadName:threadPool1550089733
ThreadName:threadPool1550089733
ThreadName:threadPool1550089733
ThreadName:threadPool865113938
ThreadName:threadPool865113938
ThreadName:threadPool118352462
ThreadName:threadPool1550089733
ThreadName:threadPool1442407170

可以看到线程池中，每个线程的创建我们都进行了记录输出与命名。

四、ThreadPoolExecutor扩展

ThreadPoolExecutor扩展主要是围绕beforeExecute()、afterExecute()和terminated()三个接口实现的，

1、beforeExecute：线程池中任务运行前执行

2、afterExecute：线程池中任务运行完毕后执行

3、terminated：线程池退出后执行

通过这三个接口我们可以监控每个任务的开始和结束时间，或者其他一些功能。下面我们可以通过代码实现一下


public class ThreadPool {
    private static ExecutorService pool;
    public static void main( String[] args ) throws InterruptedException
    {
        //实现自定义接口
        pool = new ThreadPoolExecutor(2, 4, 1000, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(5),
                new ThreadFactory() {
            public Thread newThread(Runnable r) {
                System.out.println("线程"+r.hashCode()+"创建");
                //线程命名
                Thread th = new Thread(r,"threadPool"+r.hashCode());
                return th;
            }
        }, new ThreadPoolExecutor.CallerRunsPolicy()) {
    
            protected void beforeExecute(Thread t,Runnable r) {
                System.out.println("准备执行："+ ((ThreadTask)r).getTaskName());
            }
            
            protected void afterExecute(Runnable r,Throwable t) {
                System.out.println("执行完毕："+((ThreadTask)r).getTaskName());
            }
            
            protected void terminated() {
                System.out.println("线程池退出");
            }
        };
          
        for(int i=0;i<10;i++) {
            pool.execute(new ThreadTask("Task"+i));
        }    
        pool.shutdown();
    }
}

public class ThreadTask implements Runnable{    
    private String taskName;
    public String getTaskName() {
        return taskName;
    }
    public void setTaskName(String taskName) {
        this.taskName = taskName;
    }
    public ThreadTask(String name) {
        this.setTaskName(name);
    }
    public void run() {
        //输出执行线程的名称
        System.out.println("TaskName"+this.getTaskName()+"---ThreadName:"+Thread.currentThread().getName());
    }
}

我看下输出结果

线程118352462创建
线程1550089733创建
准备执行：Task0
准备执行：Task1
TaskNameTask0---ThreadName:threadPool118352462
线程865113938创建
执行完毕：Task0
TaskNameTask1---ThreadName:threadPool1550089733
执行完毕：Task1
准备执行：Task3
TaskNameTask3---ThreadName:threadPool1550089733
执行完毕：Task3
准备执行：Task2
准备执行：Task4
TaskNameTask4---ThreadName:threadPool1550089733
执行完毕：Task4
准备执行：Task5
TaskNameTask5---ThreadName:threadPool1550089733
执行完毕：Task5
准备执行：Task6
TaskNameTask6---ThreadName:threadPool1550089733
执行完毕：Task6
准备执行：Task8
TaskNameTask8---ThreadName:threadPool1550089733
执行完毕：Task8
准备执行：Task9
TaskNameTask9---ThreadName:threadPool1550089733
准备执行：Task7
执行完毕：Task9
TaskNameTask2---ThreadName:threadPool118352462
TaskNameTask7---ThreadName:threadPool865113938
执行完毕：Task7
执行完毕：Task2
线程池退出
复制代码
可以看到通过对beforeExecute()、afterExecute()和terminated()的实现，我们对线程池中线程的运行状态进行了监控，在其执行前后输出了相关打印信息。另外使用shutdown方法可以比较安全的关闭线程池， 当线程池调用该方法后，线程池中不再接受后续添加的任务。但是，此时线程池不会立刻退出，直到添加到线程池中的任务都已经处理完成，才会退出。

五、线程池线程数量
线程吃线程数量的设置没有一个明确的指标，根据实际情况，只要不是设置的偏大和偏小都问题不大，结合下面这个公式即可

             //Nthreads=CPU数量
             //Ucpu=目标CPU的使用率，0<=Ucpu<=1
             //W/C=任务等待时间与任务计算时间的比率
           
            Nthreads = Ncpu*Ucpu*(1+W/C)

以上就是对ThreadPoolExecutor类从构造函数、拒绝策略、自定义线程创建等方面介绍了其详细的使用方法，从而我们可以根据自己的需要，灵活配置和使用线程池创建线程，
*/